package controllers;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.LongByReference;
import com.sun.jna.ptr.PointerByReference;

import play.Play;
import play.cache.Cache;
import play.libs.Codec;
import services.DrBroadCastService;
import services.SystemParamService;
import utils.BizConstants;
import utils.BroadThread;
import utils.BroadUtils;
import utils.ShellUtil;
import utils.ThreadPool;
import vos.JTTSConfig;
import vos.ResultVo;
import vos.ReturnCode;
import models.DrBroadcast;
import models.SystemOperator;


/**
 * 语音播报
 * @author wangshaoming
 *
 */
public class BroadCastController extends BaseController {
	public interface  jnaInterface extends Library{
	    int jTTS_Init(String ip,String value);
	    int jTTS_Set(JTTSConfig conf);
	    int jTTS_SessionStart(String content, PointerByReference point,int nFormat,JTTSConfig config,int nFlag,String pnBitsPerSample,String pnSamplesPerSec);
	    int jTTS_SessionExec(PointerByReference point,String callback,String hUserData);
	    int jTTS_SessionGetData(Pointer point,int index,PointerByReference voiceData,LongByReference size,int length,PointerByReference ppinsertinfo,IntByReference pninsertinfo);
	    int jTTS_SessionGetReadBytes(Pointer point,LongByReference length);
	    int jTTS_SetParam(int param,int point);
	    int jTTS_SetParam(int param,String point);
	    int jTTS_SessionStop(Pointer point);
	    int jTTS_PlayToFile(String strText, String strVoiceFile, int nFormat, JTTSConfig config, int nFlag, String callback, long userdata);
	    int jTTS_End();
	}
	/**
	 * 语音播报页
	 */
	public static void broadcast(){
		SystemOperator oper=getLoginUser();
		//验证权限
		if(BizConstants.SERVICE_ROLE.equals(oper.getRoleId())){
			render("errors/404.html");
		}
		//判断是否为管理员
		String operatorid=BizConstants.ADMIN_ROLE.equals(oper.getRoleId())?"":oper.getOperatorid();
		List<DrBroadcast> casts=DrBroadCastService.getTitleList(operatorid);
		if(casts!=null&&casts.size()>0){
			renderArgs.put("firstKey", casts.get(0).getId());
		}
		renderArgs.put("casts", casts);
		renderArgs.put("uuid", Codec.UUID());
		render();
	}
	/**
	 * 保存文本内容
	 * @param content
	 */
	public static void saveBroad(DrBroadcast cast){
		if(StringUtils.isEmpty(cast.getContent())||StringUtils.isEmpty(cast.getTitle())){
			renderRespondJson(ReturnCode.ErrorCode, "内容不可为空");
		}
		if(cast.getContent().length()>3000){
			renderRespondJson(ReturnCode.ErrorCode, "播报内容不可大于3000");
		}
		SystemOperator opr=getLoginUser();
		cast.setCreatename(opr.getOperatorid());
		cast.setId(Codec.UUID());
		cast.setCreatetime(new Date());
		cast.setIsuse(new BigDecimal(1));
		String ip=request.remoteAddress;
		boolean isSave=DrBroadCastService.saveBroad(cast,opr,ip);
		if(isSave){
			renderRespondJson(ReturnCode.SuccessCode, "保存成功");
		}
		renderRespondJson(ReturnCode.ErrorCode, "保存失败");
	}
	/**
	 * 根据id获取内容
	 * @param id
	 */
	public static void getContent(String id){
		if(StringUtils.isEmpty(id)){
			renderRespondJson(ReturnCode.ErrorCode, "请选择内容");
		}
		DrBroadcast cast=DrBroadCastService.getContentById(id);
		ResultVo vo=new ResultVo(ReturnCode.SuccessCode,"获取成功",cast);
		renderJSON(vo);
	}
	/**
	 * 删除播报记录
	 * @param id
	 */
	public static void deleteBroad(String id){
		if(StringUtils.isEmpty(id)){
			renderRespondJson(ReturnCode.ErrorCode, "请选择内容");
		}
		boolean isDel=DrBroadCastService.delBroad(id);
		if(isDel){
			renderRespondJson(ReturnCode.SuccessCode, "删除成功");
		}
		renderRespondJson(ReturnCode.ErrorCode, "服务器开小差了~~");
	}
	/**
	 * 语音播报开始
	 */
	public static void broadstart_bak(String content,String tone,String speed, String wordid){
		if(StringUtils.isEmpty(content)){
			renderRespondJson(ReturnCode.ErrorCode, "播放内容不能为空");
		}
		String path=Play.applicationPath + File.separator+BizConstants.FILE_TEMP_PATH;
		File file=new File(path);
		if(!file.isDirectory()){
			file.mkdirs();
		}
		String ptone=BizConstants.BROADCASTTONE.get(tone);
		String pspeed=BizConstants.BROADCASTSPEED.get(speed);
		String firstCon=content;
		int lastPunc=content.length();
		if(content.length()>BizConstants.CUTCONTENTLENGTH){
			firstCon=content.substring(0, BizConstants.CUTCONTENTLENGTH);
			lastPunc=BroadUtils.getLastPunc(firstCon);
			if(lastPunc<=0){
				lastPunc=BizConstants.CUTCONTENTLENGTH;
			}
			firstCon=content.substring(0, lastPunc);
		}
		String fileName=Codec.UUID();
		String videoPath=BroadUtils.postBroad(firstCon, ptone, pspeed,fileName+"_0");
		if(StringUtils.isEmpty(videoPath)){
			renderRespondJson(ReturnCode.ErrorCode, "合成语音失败");
		}
		Map<String,String>map=new HashMap<String,String>();
		map.put("videoPath", videoPath);
		map.put("fileName", fileName);
		Cache.set(fileName, "0","12h");
		if(content.length()>BizConstants.CUTCONTENTLENGTH){
			BroadThread thread =new BroadThread(fileName,videoPath,content.substring(lastPunc, content.length()),ptone,pspeed);
			ThreadPool pool=ThreadPool.getInstance();
			pool.execute(thread);
		}
		ResultVo vo=new ResultVo(ReturnCode.SuccessCode,"合成成功",map);
		renderJSON(vo);
	}
	/**
	 * 获取下一个文件地址
	 * @param name 文件名称
	 * @param path 
	 */
	public static void getBroadNext(String name,String path){
		String files=(String)Cache.get(name);
		String[] fileArray=files.split(";");
		String mp3Name=path.substring(path.lastIndexOf("_")+1, path.indexOf(".mp3"));
		String filePath=path.substring(0, path.lastIndexOf("/"));
		String next="";
		//获取本次播放文件后的一个文件
		for(int i=0;i<fileArray.length;i++){
			if(Integer.parseInt(fileArray[i])>Integer.parseInt(mp3Name)){
				next=fileArray[i];
				break;
			}
		}
		if(StringUtils.isNotEmpty(next)){
			filePath+="/"+name+"_"+next+".mp3";
			ResultVo vo=new ResultVo(ReturnCode.SuccessCode,"合成成功",filePath);
			renderJSON(vo);
		}
		//播放完毕后删除缓存
		Cache.safeDelete(name);
		renderRespondJson(ReturnCode.BroadOverCode, "播放完毕");
	}
	/**
	 * 语音合成
	 * @param content
	 * @param tone
	 */
	public static void broadstart(String content, String tone, String speed,String uuid){
		if(StringUtils.isEmpty(content)){
			renderRespondJson(ReturnCode.ErrorCode, "播放内容不能为空");
		}
		if(StringUtils.isEmpty(uuid)){
			renderRespondJson(ReturnCode.ErrorCode, "参数错误");
		}
		String path=Play.applicationPath + File.separator+BizConstants.FILE_TEMP_PATH;
		File file=new File(path);
		if(!file.isDirectory()){
			file.mkdirs();
		}
		try {
			content=new String(content.getBytes(),"UTF-8");
			int statusCode=0;
			jnaInterface instanceDll  = (jnaInterface)Native.loadLibrary("jTTS_ML",jnaInterface.class);
			String jTTSIP=SystemParamService.getValueByCacheId(BizConstants.PARAM_MAP.get("JTTS_IP"));
			String jTTSPort=SystemParamService.getValueByCacheId(BizConstants.PARAM_MAP.get("JTTS_PORT"));
			String initUrl=jTTSIP+":"+jTTSPort;
			statusCode=instanceDll.jTTS_Init(initUrl, "");
			instanceDll.jTTS_SetParam(0,65001);
			if(StringUtils.isNotEmpty(tone)){
				tone=BizConstants.BROADCASTTONE.get(tone);
				if(StringUtils.isEmpty(tone)){
					renderRespondJson(ReturnCode.ErrorCode, "请选择正确音色");
				}
				instanceDll.jTTS_SetParam(1,tone);
			}
			if(StringUtils.isNotEmpty(speed)){
				speed=BizConstants.BROADCASTSPEED.get(speed);
				if(StringUtils.isEmpty(speed)){
					renderRespondJson(ReturnCode.ErrorCode, "请选择正确语速");
				}
				instanceDll.jTTS_SetParam(4,Integer.parseInt(speed));
			}
	 		if(statusCode!=0&&statusCode!=1){
	 			log.info("初始化接口返回状态值为："+statusCode);
	 			renderRespondJson(ReturnCode.ErrorCode, "初始化接口失败");
	 		}
	 		//准备传入参数
	 		PointerByReference point = new PointerByReference();
	 		PointerByReference  strLicense = new PointerByReference();
	 		LongByReference length=new LongByReference ();
//	 		String text=new String(redCont.getBytes("UTF-8"),"UTF-8");
	 		int comByteLength=content.getBytes("UTF-8").length;
	 		int code= instanceDll.jTTS_SessionStart(content,point,0,null,0,"","");
			code=16;
			String filePath=path+uuid+".pcm";
			//打开文件输出流
			FileOutputStream byteos=new FileOutputStream(filePath,true);
			while(code!=0){
				code=instanceDll.jTTS_SessionGetData(point.getValue(),0,strLicense,length,0,new PointerByReference(),new IntByReference());
				if(code!=0&&code!=16){
					break;
				}
				if(code!=0){
	 	 			LongByReference byteSize=new LongByReference ();
	 	 			instanceDll.jTTS_SessionGetReadBytes(point.getValue(),byteSize);
	 	 			Pointer bytePonit=strLicense.getValue();
	 	 			ByteBuffer bytes=bytePonit.getByteBuffer(0, length.getValue());
	 	 			byte[] bj=new byte[bytes.remaining()];
	 	 			bytes.get(bj,0,bj.length);
	 	 			byteos.write(bj);
	 	 	        //获取本次合成文本
	 	 			int size=(int)byteSize.getValue();
	 	 			//获取进度放入缓存
	 	 			BigDecimal hasSize=new BigDecimal(size);
	 	 			BigDecimal totalByte=new BigDecimal(comByteLength);
	 	 			BigDecimal pro=hasSize.divide(totalByte, 3, BigDecimal.ROUND_HALF_EVEN);
	 	 			pro=pro.multiply(new BigDecimal(100));
	 	 			if(pro.intValue()<100){
	 	 				if(pro.intValue()==0){
	 	 					pro=new BigDecimal(1);
	 	 				}
	 	 				Cache.set(uuid, Integer.toString(pro.intValue()));
	 	 			}
	 			}
	 			else{
	 				break;
	 			}
			}
			//关闭文件输出流
			byteos.close();
			if(StringUtils.isNotEmpty(filePath)){
				String Mp3path=filePath.substring(0,filePath.lastIndexOf(".")+1)+"mp3";
				path=path.substring(0,path.lastIndexOf(".")+1)+"mp3";
				ResultVo vo=pcmToMp3(filePath,Mp3path);
				if(vo.code==200){
					Cache.set(uuid, Integer.toString(100));
					renderJSON(vo);
				}else{
					renderJSON(vo);
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			renderRespondJson(ReturnCode.ErrorCode,"播报内容未被识别");
		}
		
	}
	/**
	 * pcm转MP3
	 * @param cases 案件信息
	 * @param videoUrl 存放pcm地址
	 * @param isCompel 是否强制提交
	 * @return
	 */
	public static ResultVo pcmToMp3(String pcmPath,String videoUrl){
		ResultVo vo=new ResultVo(ReturnCode.SuccessCode);
		//将pcm 转为MP3
		String mp3url=SystemParamService.getValueByCacheId(BizConstants.PARAM_MAP.get("PCM_MP3_IP"));
		String map3user=SystemParamService.getValueByCacheId(BizConstants.PARAM_MAP.get("PCM_MP3_USER"));
		String mp3pass=SystemParamService.getValueByCacheId(BizConstants.PARAM_MAP.get("PCM_MP3_PASS"));
		String mp3Shell=SystemParamService.getValueByCacheId(BizConstants.PARAM_MAP.get("SSH_PCM_TO_MP3_SHELL"));
		//将pcm 转为MP3
		if(StringUtils.isEmpty(mp3Shell)||StringUtils.isEmpty(map3user)||
				StringUtils.isEmpty(mp3pass)){
			vo=new ResultVo(ReturnCode.ErrorCode,"转mp3失败:系统参数未设置");
			return vo;
		}
		String shelltext="cd "+mp3Shell+"&& ./PcmToMp3.sh "+
				pcmPath+" "+videoUrl;
		System.out.println(shelltext);
		Map<String,Object> shellMap=ShellUtil.execAndPass(mp3url,map3user,mp3pass,shelltext);
		if(shellMap!=null){
			int shellsta=(int)shellMap.get("status");
			if(shellsta!=0){
				if(StringUtils.isNotEmpty((String)shellMap.get("outErr"))){
					log.info((String)shellMap.get("outErr"));
				}
			}
			//执行成功后将pcm文件删除
			else{
				File file=new File(videoUrl);
				if(file.exists()&&file.length()>0){
					File pcmfile = new File(pcmPath);
					if(pcmfile.exists()){
						pcmfile.delete();
					}
				}
			}
		}
		return vo;
	}
	/**
	 * 获取进度
	 * @param uuid
	 */
	public static void getProcess(String uuid){
		String pro=(String)Cache.get(uuid);
		if("100".equals(pro)){
			Cache.delete(uuid);
		}
		renderText(pro);
	}
}
